﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace KopeykaStore.Models
{
    public class ShoppingCart
    {
        public const string CartSessionKey = "CartId";
        private readonly KopeykaStoreEntities storeDB = new KopeykaStoreEntities();

        private string ShoppingCartId { get; set; }

        public static ShoppingCart GetCart(HttpContextBase context)
        {
            var cart = new ShoppingCart();
            cart.ShoppingCartId = cart.GetCartId(context);
            return cart;
        }

        // Helper method to simplify shopping cart calls
        public static ShoppingCart GetCart(Controller controller)
        {
            return GetCart(controller.HttpContext);
        }

        public void AddToCart(Product product)
        {
            // Get the matching cart and Product instances
            Cart cartItem = storeDB.Carts.SingleOrDefault(
                c => c.CartId == ShoppingCartId && c.ProductId == product.ProductId);

            if (cartItem == null)
            {
                // Create a new cart item if no cart item exists
                cartItem = new Cart
                               {
                                   ProductId = product.ProductId,
                                   CartId = ShoppingCartId,
                                   Count = 1,
                                   DateCreated = DateTime.Now,
                               };

                storeDB.Carts.Add(cartItem);
            }
            else
            {
                // If the item does exist in the cart, then add one to the quantity
                cartItem.Count++;
            }

            // Save changes
            storeDB.SaveChanges();
        }

        public int RemoveFromCart(int id)
        {
            // Get the cart
            Cart cartItem = storeDB.Carts.Single(cart => cart.CartId == ShoppingCartId && cart.RecordId == id);

            int itemCount = 0;

            if (cartItem != null)
            {
                if (cartItem.Count > 1)
                {
                    cartItem.Count--;
                    itemCount = cartItem.Count;
                }
                else
                {
                    storeDB.Carts.Remove(cartItem);
                }

                // Save changes
                storeDB.SaveChanges();
            }

            return itemCount;
        }

        public void EmptyCart()
        {
            IQueryable<Cart> cartItems = storeDB.Carts.Where(cart => cart.CartId == ShoppingCartId);

            foreach (Cart cartItem in cartItems)
            {
                storeDB.Carts.Remove(cartItem);
            }

            // Save changes
            storeDB.SaveChanges();
        }

        public List<Cart> GetCartItems()
        {
            return storeDB.Carts.Where(cart => cart.CartId == ShoppingCartId).ToList();
        }

        public int GetCount()
        {
            // Get the count of each item in the cart and sum them up
            int? count = (from cartItems in storeDB.Carts
                          where cartItems.CartId == ShoppingCartId
                          select (int?) cartItems.Count).Sum();

            // Return 0 if all entries are null
            return count ?? 0;
        }

        public decimal GetTotal()
        {
            // Multiply Product price by count of that Product to get 
            // the current price for each of those Products in the cart
            // sum all Product price totals to get the cart total cartItems.Product.Price
            decimal? total = (from cartItems in storeDB.Carts
                              where cartItems.CartId == ShoppingCartId
                              select (int?)cartItems.Count*1).Sum();
            return total ?? decimal.Zero;
        }

        public decimal GetCostTotal()
        {
            // Multiply Product price by count of that Product to get 
            // the current price for each of those Products in the cart
            // sum all Product price totals to get the cart total cartItems.Product.Price
            decimal? total = (from cartItems in storeDB.Carts
                              where cartItems.CartId == ShoppingCartId
                              select (int?)cartItems.Count * cartItems.Product.Price).Sum();
            return total ?? decimal.Zero;
        }

        public decimal GetItemCostTotal(int id)
        {
            Cart cartItem = storeDB.Carts.Single(cart => cart.CartId == ShoppingCartId && cart.RecordId == id);
            decimal cartItemCount = (decimal)cartItem.Count;
            decimal cartItemPrice = (decimal)cartItem.Product.Price;

            return cartItemCount * cartItemPrice;

        }

        public int CreateOrder(Order order)
        {
            decimal orderTotal = 0;

            List<Cart> cartItems = GetCartItems();

            // Iterate over the items in the cart, adding the order details for each
            foreach (Cart item in cartItems)
            {
                var orderDetail = new OrderDetail
                                      {
                                          ProductId = item.ProductId,
                                          OrderId = order.OrderId,
                                          UnitPrice = item.Product.Price,
                                          Quantity = item.Count
                                      };

                // Set the order total of the shopping cart
                orderTotal += (item.Count*item.Product.Price);

                storeDB.OrderDetails.Add(orderDetail);
            }

            // Set the order's total to the orderTotal count
            order.Total = orderTotal;

            // Save the order
            storeDB.SaveChanges();

            // Empty the shopping cart
            EmptyCart();

            // Return the OrderId as the confirmation number
            return order.OrderId;
        }

        // We're using HttpContextBase to allow access to cookies.
        public string GetCartId(HttpContextBase context)
        {
            if (context.Session[CartSessionKey] == null)
            {
                if (!string.IsNullOrWhiteSpace(context.User.Identity.Name))
                {
                    context.Session[CartSessionKey] = context.User.Identity.Name;
                }
                else
                {
                    // Generate a new random GUID using System.Guid class
                    Guid tempCartId = Guid.NewGuid();

                    // Send tempCartId back to client as a cookie
                    context.Session[CartSessionKey] = tempCartId.ToString();
                }
            }

            return context.Session[CartSessionKey].ToString();
        }

        // When a user has logged in, migrate their shopping cart to
        // be associated with their username
        public void MigrateCart(string userName)
        {
            IQueryable<Cart> shoppingCart = storeDB.Carts.Where(c => c.CartId == ShoppingCartId);

            foreach (Cart item in shoppingCart)
            {
                item.CartId = userName;
            }
            storeDB.SaveChanges();
        }
    }
}